//
//  LLDateUtil.swift
//  LiLi
//
//  Created by liuzhu on 2019/1/9.
//  Copyright © 2019 liuzhu. All rights reserved.
//

import UIKit

class LLDateUtil: NSObject {
    
    var chineseMonths = ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"]
    var chineseDays = ["初一","初二","初三","初四","初五","初六","初七","初八","初九","初十","十一","十二","十三","十四","十五","十六","十七","十八","十九","二十","廿一","廿二","廿三","廿四","廿五","廿六","廿七","廿八","廿九","三十"]
    var Zodiacs = ["鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"]
    
    static let tools:LLDateUtil = {
        let t = LLDateUtil()
        return t
    }()
    
    //获取单例
    class func shareLLDateUtil()->LLDateUtil{
        return tools
    }
    
    //获取当前日期时间
    public func getCurrentDate() -> Date{
        let currentDate = Date()   //格林时间，比北京时间早8小时
        let zone = NSTimeZone.system    //获取当前系统时区
        let interval = zone.secondsFromGMT()   //获取当前时区与GMT时区间隔
        let localeDate = currentDate.addingTimeInterval(TimeInterval(interval)) //获取当前时间
        return localeDate
    }
    
    //获取明天日期时间
    public func getTomorrowDate() -> Date{
        let currentDate = getCurrentDate()
        let interval = 24*60*60
        let localeDate = currentDate.addingTimeInterval(TimeInterval(interval))
        return localeDate
    }
    
    //获取以今天为起点某天的日期
    public func getOneDateFromToday(interval:Int) -> Date{
        let currentDate = getCurrentDate()
        let timeInterval = interval*24*60*60
        let localeDate = currentDate.addingTimeInterval(TimeInterval(timeInterval))
        return localeDate
    }
    
    //获取某一天所在周的周一或周二或...的日期dateStr
    public func getDateStrOfTodayInWeek(week:Int) -> String{
        let todayWeek = currentWeek()
        let todayIsWeek = (todayWeek - 1) <= 0 ? 7 :(todayWeek - 1)
        let interval = week - todayIsWeek
        let date = getOneDateFromToday(interval: interval)
        return dateConverString(date: date, dateFormat: "yyyy-MM-dd")
    }
    
    //获取下周x的dateStr
    public func getDateStrOfNextWeek(week:Int) -> String{
        let todayWeek = currentWeek()
        let todayIsWeek = (todayWeek - 1) <= 0 ? 7 :(todayWeek - 1)
        let interval = week + 7 - todayIsWeek
        let date = getOneDateFromToday(interval: interval)
        return dateConverString(date: date, dateFormat: "yyyy-MM-dd")
    }
    
    //获取下个月几号的dateStr
    public func getDateStrOfNextMonth(day:Int) ->String{
        let currentMonthDayCount = getDaysInMonth(year: currentYear(), month: currentMonth())
        let interval = day + currentMonthDayCount - currentDay()
        let date = getOneDateFromToday(interval: interval)
        return dateConverString(date: date, dateFormat: "yyyy-MM-dd")
    }
    
    //获取明年的几月月几号的dateStr
    public func getDateStrOfNextYear(month:Int,day:Int) ->String{
        let arr = getDayStrListRepeatYearSun(year: currentYear(), month: month, day: day)
        if  arr.count != 0 {
            var dateStr = "3000-01-01"
            for str in arr{
                let strArr = str.components(separatedBy: "-")
                let foryear = Int(strArr[0])
                let formonth = Int(strArr[1])
                let forday = Int(strArr[2])
                if(foryear != currentYear() && formonth == month && forday == day){
                    dateStr = String(format: "%04d-%02d-%02d", foryear!,formonth!,forday!)
                    break
                }
            }
             return dateStr
        }else{
            return "3000-01-01"
        }
    }
    
    public func getSunDateStrWithMoonDay(day:Int)->String{
        //根据农历初几反推出是公历本月几号
        //获取今天是初几
        let chineseDay = currentChineseDay()
        let interval = (day - chineseDay) //>= 0 ? (day-chineseDay) : getDaysFromTodayToChineseDay(day: day)
        return dateConverString(date:  getOneDateFromToday(interval: interval), dateFormat: "yyyy-MM-dd")
    }
    
    //j直接计算出用户选中的农历日期的合适提醒日
    public func getSunDateStrWithMoonMonthDay(month:Int,day:Int,hour:Int,min:Int) ->String{
        //获取从今天开始之后所有年的农历几月初几
        var dateStr = [String]()
        //今天是农历几月初几
        for y in (currentYear() - 1)...maxYear{ //农历一般会比公历晚一年，保险起见，往前多算一年
            for m in 1...12{
                let dayCountOfMonth = getDaysInMonth(year: y, month:m)
                for i in 1...dayCountOfMonth{
                    let str = String(format: "%04d-%02d-%02d", y,m,i)
                    let fordate = stringConvertDate(string: str,dateFormat:"yyyy-MM-dd")
                    let calendarChinese:Calendar = Calendar(identifier: .chinese)
                    let formonth = calendarChinese.component(.month, from: fordate)
                    let forday = calendarChinese.component(.day, from: fordate)
                    if formonth == month && forday == day{
                        dateStr.append(str)
                    }
                }
            }
        }
        if dateStr.count != 0 {
            let timeStr = String(format: "%02d:%02d", hour,min)
            let currentTime = getCurrentDate()
            for str in dateStr{
                let forDateStr = "\(str) \(timeStr):00"
                let forDate = stringConvertDate(string: forDateStr, dateFormat: "yyyy-MM-dd HH:mm:ss")
                if compareDate(date1: forDate, date2: currentTime) > 0{
                    return str
                }
            }
            return "3000-01-01"
        }
        return "3000-01-01"
    }
    
    //获取下个月农历初几是公历几号
    public func getNextSunDateStrWithMoonDay(day:Int)->String{
        //根据农历初几反推出是公历本月几号
        let interval = getDaysFromTodayToChineseDay(day: day)
        return dateConverString(date:  getOneDateFromToday(interval: interval), dateFormat: "yyyy-MM-dd")
    }
    
    //获取农历今天和未来!!的初几相差多少天
    private func getDaysFromTodayToChineseDay(day:Int) -> Int{
        var count = 0
        var chineseDay = currentChineseDay()
        repeat {
            count = count + 1
            let date = getOneDateFromToday(interval: count)
            let calendarChinese:Calendar = Calendar(identifier: .chinese)
            chineseDay = calendarChinese.component(.day, from: date)
        }while  day != chineseDay
//        while day != chineseDay{
//            count = count + 1
//            let date = getOneDateFromToday(interval: count)
//            let calendarChinese:Calendar = Calendar(identifier: .chinese)
//            chineseDay = calendarChinese.component(.day, from: date)
//
//        }
        //获取今天是初几
        return count
    }
    
    //MARK:-工具方法
    //当前年
    public func currentYear()->Int{
        let date = getCurrentDate()
        let calendarChinese:Calendar = Calendar(identifier: .gregorian)
        let year = calendarChinese.component(.year, from: date)
        return year
    }
    //当前月
    public func currentMonth()->Int{
        let date = getCurrentDate()
        let calendarChinese:Calendar = Calendar(identifier: .gregorian)
        let month = calendarChinese.component(.month, from: date)
        return month
    }
    
    //当前周
    public func currentWeek()->Int{
        let date = getCurrentDate()
        var calendarChinese:Calendar = Calendar(identifier: .gregorian)
        calendarChinese.timeZone = (NSTimeZone.init(abbreviation: "UTC")! as TimeZone)
        let week = calendarChinese.component(.weekday, from: date)
        return week
    }
    
    //当前日
    public func currentDay()->Int{
        let date = getCurrentDate()
        var calendarChinese:Calendar = Calendar(identifier: .gregorian)
        calendarChinese.timeZone = (NSTimeZone.init(abbreviation: "UTC")! as TimeZone)
        let week = calendarChinese.component(.day, from: date)
        return week
    }
    
    //当前农历初几
    public func currentChineseDay()->Int{
        let date = getCurrentDate()
        let dateStr = dateConverString(date: date, dateFormat: "yyyy-MM-dd")
        let newDate = stringConvertDate(string: dateStr, dateFormat: "yyyy-MM-dd")
        let calendarChinese:Calendar = Calendar(identifier: .chinese)
        let day = calendarChinese.component(.day, from: newDate)
        return day
    }
    
    
    //根据字符串日期返回Date
    func stringConvertDate(string:String, dateFormat:String) -> Date {
        let dateFormatter = DateFormatter.init()
        dateFormatter.dateFormat = dateFormat
        let date = dateFormatter.date(from: string)//格林时间date
        let zone = NSTimeZone.system    //获取当前系统时区
        let interval = zone.secondsFromGMT()   //获取当前时区与GMT时区间隔
        let localeDate = date!.addingTimeInterval(TimeInterval(interval)) //获取当前时间
        return localeDate
    }
    
    //比较两个date大小(1 date1大于date2，0 date1等于date2，-1 date1小于date2)
    func compareDate(date1:Date,date2:Date) -> Int {
        if date1.compare(date2) == .orderedAscending{
            return -1
        }else if date1.compare(date2) == .orderedSame{
           return 0
        }else {//if date1.compare(date2) == .orderedDescending{
           return 1
        }
    }
    
    //根据Date返回字符串
    func dateConverString(date:Date,dateFormat:String) -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = dateFormat
        dateFormatter.timeZone = (NSTimeZone.init(abbreviation: "UTC")! as TimeZone)
          //dateFormatter.locale = Locale.init(identifier: "zh_CN")
        let stringTime = dateFormatter.string(from: date)
        return stringTime
    }
    
    //根据公立日期返回农历日期(Date(yyyy-mm-dd)->String(mm-dd))
    func gregorianToChineseDate(gregorianDate:Date) -> String {
        let calendarChinese:Calendar = Calendar(identifier: .chinese)
        _ = calendarChinese.component(.year, from: gregorianDate)
        let month = calendarChinese.component(.month, from: gregorianDate)
        var day = calendarChinese.component(.day, from: gregorianDate)
        if day == 0{
            day = 30
        }
        let returnDateStr = "\(chineseMonths[month-1])-\(chineseDays[day-1])"
        return returnDateStr
    }
    
    //根据公立日期返回农历日(Date(yyyy-mm-dd)->String(dd))
    func gregorianToChineseDay(gregorianDate:Date) -> String {
        let calendarChinese:Calendar = Calendar(identifier: .chinese)
        _ = calendarChinese.component(.year, from: gregorianDate)
        let day = calendarChinese.component(.day, from: gregorianDate)
        let returnDateStr = "\(chineseDays[day-1])"
        return returnDateStr
    }
    
    //根据日期获取农历年
    func getChineseYear(date:Date) -> String {
        let calendarChinese:Calendar = Calendar(identifier: .chinese)
        let year = calendarChinese.component(.year, from: date)
        let zodiacIndex: Int = (year - 1) % Zodiacs.count
        let returnDateStr = "\(Zodiacs[zodiacIndex])"
        return returnDateStr
    }
    
    //根据日期获取周几
    func getWeekDay(date:Date) -> Int {
        let calendarChinese:Calendar = Calendar(identifier: .gregorian)
        let weekDay = calendarChinese.component(.weekday, from: date)
        return weekDay
    }
    
    //获取当前年月
    func getCurrentYearAndMonth() -> String {
        let date = getCurrentDate()
        return dateConverString(date: date, dateFormat: "yyyy-MM")
    }
    
    //获取当前年月日
    func getCurrentYearAndMonthAndDay() -> String {
        let date = getCurrentDate()
        return dateConverString(date: date, dateFormat: "yyyy-MM-dd")
    }
    
    //计算指定月天数
    func getDaysInMonth( year: Int, month: Int) -> Int
    {
        let dateComponents = DateComponents(year: year ,month: month)
        let date = Calendar.current.date(from: dateComponents)!
        let zone = NSTimeZone.system    //获取当前系统时区
        let interval = zone.secondsFromGMT()   //获取当前时区与GMT时区间隔
        let localeDate = date.addingTimeInterval(TimeInterval(interval)) //获取当前时间
        let range = Calendar.current.range(of: .day, in: .month,for: localeDate)
        return range?.count ?? 0
    }
    
    //计算指定年天数
    func getDaysInYear(year: Int) -> Int
    {
        let dateComponents = DateComponents(year: year)
        let date = Calendar.current.date(from: dateComponents)!
        let zone = NSTimeZone.system    //获取当前系统时区
        let interval = zone.secondsFromGMT()   //获取当前时区与GMT时区间隔
        let localeDate = date.addingTimeInterval(TimeInterval(interval)) //获取当前时间
        let range = Calendar.current.range(of: .day, in: .year,for: localeDate)
        return range?.count ?? 0
    }
    
    /// 获取某月的所有有效日期字符串
    ///
    /// - Parameter yearAndMonth: xxxx-xx
    /// - Returns: xxxx-xx-xx
    func getDayStrListWithMonth(yearAndMonth:String)->[String]?{
        //计算本月有多少天
        if yearAndMonth.contains("-"){
            let arr = yearAndMonth.components(separatedBy: "-")
            let year = Int(arr.first!)
            let month = Int(arr.last!)
            let dayCountOfMonth = getDaysInMonth(year: year!, month: month!)
            var dates = [String]()
            for i in 1...dayCountOfMonth{
                let dateStr = String(format: "%04d-%02d-%02d", year!,month!,i)
                dates.append(dateStr)
            }
            return dates
        }
        return nil
    }
    
    //MARK:- 计算重复日期方法
    func getDayStrListAfterTheDay(dateStr:String,repeatTag:ActionRepeatTag)->[String]?{
        if !dateStr.contains("-") {
            return nil
        }
        let arr = dateStr.components(separatedBy: "-")
        let year = Int(arr.first!)
        let month = Int(arr[1])
        let day = Int(arr.last!)
        var datestrList = [String]()
        switch repeatTag {
        case .REPEAT_DAY:
            //按天算
            datestrList = getDayStrListRepeatDay(year: year!, month: month!, day: day!)
            break
        case .REPEAT_WEEK:
            //按周算
            datestrList = getDayStrListRepeatWeek(year: year!, month: month!, day: day!)
            break
        case .REPEAT_MONTH_SUN:
            //按公历月算
            datestrList = getDayStrListRepeatMonthSun(year: year!, month: month!, day: day!)
            break
        case .REPEAT_MONTH_MOON:
            //按农历月算
            datestrList = getDayStrListRepeatMonthMoon(year: year!, month: month!, day: day!)
            break
        case .REPEAT_YEAR_SUN:
            //按公历年算
            datestrList = getDayStrListRepeatYearSun(year: year!, month: month!, day: day!)
            break
        case .REPEAT_YEAR_MOON:
            //按农历年算
            datestrList = getDayStrListRepeatYearMoon(year: year!, month: month!, day: day!)
            break
        default:
            //一次性提醒，不重复，直接返回Action当天
           datestrList.append(dateStr)
        }
        return datestrList
    }
    
    private func getDayStrListRepeatDay(year:Int,month:Int,day:Int) -> [String] {
        var dateStr = [String]()
        for y in year...maxYear{   //第一重循环 按年循环
            if y == year{//先算本年的剩余月份
                for m in month...12{
                    let dayCountOfMonth = getDaysInMonth(year: y, month:m)
                    if(m == month){//本月只算剩余天数
                        for i in day...dayCountOfMonth{
                            let str = String(format: "%04d-%02d-%02d", y,m,i)
                            dateStr.append(str)
                        }
                    }else{
                        for i in 1...dayCountOfMonth{
                            let str = String(format: "%04d-%02d-%02d", y,m,i)
                            dateStr.append(str)
                        }
                    }
                }
            }else{//算之后每年的月份
                for m in 1...12{
                    let dayCountOfMonth = getDaysInMonth(year: y, month:m)
                    for i in 1...dayCountOfMonth{
                        let str = String(format: "%04d-%02d-%02d", y,m,i)
                        dateStr.append(str)
                    }
                }
            }
        }
        return dateStr
    }
    
   private func getDayStrListRepeatWeek(year:Int,month:Int,day:Int) -> [String] {
        var dateStr = [String]()
        //今天是周几
        let temDateStr = String(format: "%04d-%02d-%02d", year,month,day)
        let date = stringConvertDate(string: temDateStr,dateFormat:"yyyy-MM-dd")
        let todayWeek = getWeekDay(date: date)
        
        for y in year...maxYear{   //第一重循环 按年循环
            if y == year{//先算本年的剩余月份
                for m in month...12{
                    let dayCountOfMonth = getDaysInMonth(year: y, month:m)
                    if m == month{
                        for i in day...dayCountOfMonth{
                            let str = String(format: "%04d-%02d-%02d", y,m,i)
                            let fordate = stringConvertDate(string: str,dateFormat:"yyyy-MM-dd")
                            let forweek = getWeekDay(date: fordate)
                            if forweek == todayWeek{
                                dateStr.append(str)
                            }
                        }
                    }else{
                        for i in 1...dayCountOfMonth{
                            let str = String(format: "%04d-%02d-%02d", y,m,i)
                            let fordate = stringConvertDate(string: str,dateFormat:"yyyy-MM-dd")
                            let forweek = getWeekDay(date: fordate)
                            if forweek == todayWeek{
                                dateStr.append(str)
                            }
                        }
                    }
                }
            }else{//算之后每年的月份
                for m in 1...12{
                    let dayCountOfMonth = getDaysInMonth(year: y, month:m)
                    for i in 1...dayCountOfMonth{
                        let str = String(format: "%04d-%02d-%02d", y,m,i)
                        let fordate = stringConvertDate(string: str,dateFormat:"yyyy-MM-dd")
                        let forweek = getWeekDay(date: fordate)
                        if forweek == todayWeek{
                            dateStr.append(str)
                        }
                    }
                }
            }
        }
        return dateStr
    }
    
   private func getDayStrListRepeatMonthSun(year:Int,month:Int,day:Int) -> [String] {
        var dateStr = [String]()
        for y in year...maxYear{   //第一重循环 按年循环
            if y == year{//先算本年的剩余月份
                for m in month...12{
                    let dayCountOfMonth = getDaysInMonth(year: y, month:m)
                    for i in 1...dayCountOfMonth{
                        if i == day{
                            let str = String(format: "%04d-%02d-%02d", y,m,i)
                            dateStr.append(str)
                        }
                    }
                }
            }else{//算之后每年的月份
                for m in 1...12{
                    let dayCountOfMonth = getDaysInMonth(year: y, month:m)
                    for i in 1...dayCountOfMonth{
                        if i == day{
                            let str = String(format: "%04d-%02d-%02d", y,m,i)
                            dateStr.append(str)
                        }
                    }
                }
            }
        }
        return dateStr
    }
    
   private func getDayStrListRepeatMonthMoon(year:Int,month:Int,day:Int) -> [String] {
        var dateStr = [String]()
        //今天是农历初几
        let temDateStr = String(format: "%04d-%02d-%02d", year,month,day)
        let date = stringConvertDate(string: temDateStr,dateFormat:"yyyy-MM-dd")
        let chineseDay = gregorianToChineseDay(gregorianDate: date)
        
        for y in year...maxYear{   //第一重循环 按年循环
            if y == year{//先算本年的剩余月份
                for m in month...12{
                    let dayCountOfMonth = getDaysInMonth(year: y, month:m)
                    for i in 1...dayCountOfMonth{
                        let str = String(format: "%04d-%02d-%02d", y,m,i)
                        let fordate = stringConvertDate(string: str,dateFormat:"yyyy-MM-dd")
                        let forchineseDay = gregorianToChineseDay(gregorianDate: fordate)
                        if forchineseDay == chineseDay{
                            dateStr.append(str)
                        }
                    }
                }
            }else{//算之后每年的月份
                for m in 1...12{
                    let dayCountOfMonth = getDaysInMonth(year: y, month:m)
                    for i in 1...dayCountOfMonth{
                        let str = String(format: "%04d-%02d-%02d", y,m,i)
                        let fordate = stringConvertDate(string: str,dateFormat:"yyyy-MM-dd")
                        let forchineseDay = gregorianToChineseDay(gregorianDate: fordate)
                        if forchineseDay == chineseDay{
                            dateStr.append(str)
                        }
                    }
                }
            }
        }
        return dateStr
    }
    
   private func getDayStrListRepeatYearSun(year:Int,month:Int,day:Int) -> [String] {
        var dateStr = [String]()
        for y in year...maxYear{
            for m in 1...12{
                let dayCountOfMonth = getDaysInMonth(year: y, month:m)
                for i in 1...dayCountOfMonth{
                    let str = String(format: "%04d-%02d-%02d", y,m,i)
                    if m == month && i == day{
                        dateStr.append(str)
                    }
                }
            }
        }
        return dateStr
    }
    
   private func getDayStrListRepeatYearMoon(year:Int,month:Int,day:Int) -> [String] {
        var dateStr = [String]()
        //今天是农历几月初几
        let temDateStr = String(format: "%04d-%02d-%02d", year,month,day)
        let date = stringConvertDate(string: temDateStr,dateFormat:"yyyy-MM-dd")
        let chineseDate = gregorianToChineseDate(gregorianDate: date)
        for y in year...maxYear{
            for m in 1...12{
                let dayCountOfMonth = getDaysInMonth(year: y, month:m)
                for i in 1...dayCountOfMonth{
                    let str = String(format: "%04d-%02d-%02d", y,m,i)
                    let fordate = stringConvertDate(string: str,dateFormat:"yyyy-MM-dd")
                    let forchineseDate = gregorianToChineseDate(gregorianDate: fordate)
                    if forchineseDate == chineseDate{
                        dateStr.append(str)
                    }
                }
            }
        }
        return dateStr
    }
}
